<?php

declare(strict_types=1);
/**
 * Author: Zane
 * Email: 873934580@qq.com
 * Date: 2022/4/7.
 */

namespace Zane\TableHandle;

use App\Enum\DefaultFieldEnum;
use App\Exceptions\CommonExceptionConstants;
use App\Exceptions\ServiceException;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;

abstract class Base implements IBase
{
    protected $model;
    protected $origin;
    protected $tableName;
    protected $fieldType;

    public function handle(): void
    {
        $this->tableName = getTableName($this->model->parentModel->table_name);
        $current = $this;
        $this->isExists();
        // 如果字段名称有更新先更新字段名称
        if ($this->isNameEdit()) {
            Schema::table($this->tableName, function (Blueprint $table) use ($current): void {
                $table->renameColumn($current->origin->field, $current->model->field);
            });
        }

        Schema::table($this->tableName, function (Blueprint $table) use ($current): void {
            $param = $current->getParam();

            $tableField = $table->{$current->getFieldType()}(...$param);
            // 设置是否为空
            if (!$current->model->is_required) {
                $tableField->nullable();
            }
            // 设置备注
            $tableField->comment($current->model->title);
            // 设置默认值
            if (null !== $current->getDefaultVal()) {
                $tableField->default($current->getDefaultVal());
            }
            // 设置无符号
            if ($current->isUnsigned()) {
                $tableField->unsigned();
            }

            // 属于更新还是新增
            if ($current->origin) {
                $tableField->change();
            } else {
                $tableField->after($current->getAfter());
            }
        });
    }

    public function setModel($model): IBase
    {
        $this->model = $model;

        return $this;
    }

    public function setOrigin($model): IBase
    {
        $this->origin = $model;

        return $this;
    }

    /**
     * @param mixed $data
     *
     * @throws ValidationException
     */
    public function checkRule($data): void
    {
        $rule = $this->getRules();
        if (!$rule) {
            return;
        }

        $validator = Validator::make($data, $rule, $this->getMessage());
        if ($validator->fails()) {
            throw new ValidationException($validator);
        }
    }

    public function parseRule($param, $isRequired): array
    {
        return [];
    }

    /**
     * 保存时将数据转译后返回.
     *
     * @param $val
     * @param $param
     *
     * @return mixed
     */
    public function getSaveVal($val, $param)
    {
        return $val;
    }

    /**
     * 展示时将数据转译后展示.
     *
     * @param $val
     * @param $param
     *
     * @return mixed
     */
    public function getVal($val, $param)
    {
        return $val;
    }

    public function getRules(): array
    {
        return [];
    }

    protected function getDefaultVal()
    {
        return $this->model->default_val;
    }

    /**
     * 返回字段的参数信息.
     *
     * @return array
     */
    protected function getParam(): array
    {
        return [$this->model->field];
    }

    /**
     * 解析扩展参数.
     *
     * @return array
     */
    protected function parse(): array
    {
        return $this->model->param ? json_decode($this->model->param, true) : [];
    }

    /**
     * 设置 INTEGER 类型的字段为 UNSIGNED (MySQL).
     *
     * @return bool
     */
    protected function isUnsigned(): bool
    {
        return false;
    }

    /**
     * 是否允许更新.
     *
     * @return bool
     */
    protected function isAllowUpdate(): bool
    {
        return true;
    }

    /**
     * 设置验证的提示信息.
     *
     * @return array
     */
    protected function getMessage(): array
    {
        return [];
    }

    protected function getFieldType()
    {
        return $this->fieldType;
    }

    /**
     * 设置字段新增的修饰信息.
     *
     * @param $table
     * @param $default
     * @param $isInsert
     */
    protected function setFieldAdorn($table, $default, $isInsert): void
    {
        $table->after($this->getAfter());
        $table->default($default);
        if (!$isInsert) {
            $table->change();
        }
    }

    protected function getAfter(): string
    {
        return DefaultFieldEnum::ID;
    }

    private function isNameEdit(): bool
    {
        if ($this->origin && $this->origin->field !== $this->model->field) {
            if (Schema::hasColumn($this->tableName, $this->origin->field)) {
                return true;
            }
        }

        return false;
    }

    /**
     * 验证字段是否已经在数据表中.
     */
    private function isExists(): void
    {
        if ($this->origin) {
            if ($this->model->field !== $this->origin->field && Schema::hasColumn($this->tableName, $this->model->field)) {
                throw new ServiceException(CommonExceptionConstants::DATA_IS_EXISTS);
            }
        } else {
            if (Schema::hasColumn($this->tableName, $this->model->field)) {
                throw new ServiceException(CommonExceptionConstants::DATA_IS_EXISTS);
            }
        }
    }
}
